from datetime import datetime

from flask import Flask,render_template,abort,flash,redirect,url_for,request

from models import db,News,mongodb,Comments

from forms import NewsForm_mysql,CommentForm

from cache import NewsCache

app = Flask(__name__)
# 加载配置文件
app.config.from_object('conf.Config')
# # 配置---mysql数据库链接的配置参数
# app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1/flask_news'
# # 使用表单flask_wtf 需要配置一个SECRET_KEY  配置就行 具体使用不知
# app.config['SECRET_KEY'] = 'this is a random key string'
#
# # 配置----MongoDB
# app.config['MONGODB_SETTINGS'] = {
#     'db':'flask_news',
#     # "username":"webapp",
#     # "password":"pwd123"
# }


# flask和SQLAlchemy关联一下
# db = SQLAlchemy(app)
# db = SQLAlchemy()
db.init_app(app=app)
# flask和flask_mongoengine关联一下:方式一
# mongodb = MongoEngine(app)
# flask和flask_mongoengine关联一下:方式二
# mongodb = MongoEngine()
mongodb.init_app(app=app)







# 创建好模型类，需要同步到数据库中
# 1.在python console中  输入
# from app import db （app是app.py）
# db.create_all()即可(使用这个报错了  没有上下文的错误)

# 使用modelToDatabase可以，定位到当前目录
# 定位到当前目录的方式（打开设置File → Settings → Build, Execution, Deployment → Console → Python Console。）
# 在Working directory中填写目标路径，例如（D:\freedong\zhuzhu\FullStackEngineer2025\507python_operate_three_databases\4.flask_news(自动生成)）
# 在python console中  输入
# 执行from app import modelToDatabase 然后执行modelToDatabase()模型同步到数据库成功
def modelToDatabase():
    with app.app_context():
        db.create_all()

# 前台页面--首页
@app.route('/')
def index():  # put application's code here
    # news_list = News.query.filter(News.is_valid == 1,News.is_top == 1).all()
    # 从缓存中获取首页新闻
    cache_obj = NewsCache()
    news_list = cache_obj.get_index_news()
    print(news_list[0])
    return render_template('index.html',news_list=news_list)

# 前台页面--分类
@app.route('/cat/<news_type>')
def cat(news_type):
    # 新闻分类页
    news_list = News.query.filter(News.news_type == news_type,News.is_valid == 1).all()
    print(news_list)
    return render_template('cat.html',news_list=news_list,news_type=news_type)

# 前台页面--新闻详情页
@app.route('/detail/<pk>')
def detail(pk):
    # 新闻详情页
    form = CommentForm(data={'object_id':pk})
    new_obj = News.query.get(pk)
    if not new_obj.is_valid:
        abort(404)
    return render_template('detail.html',new_obj=new_obj,form=form)



@app.route("/comment/<int:news_id>/add",methods=["POST"])
def comment_add(news_id):
    # "新增评论"
    new_obj = News.query.get(news_id)
    form = CommentForm(data={'object_id':news_id})
    if form.validate_on_submit():
        comment_obj = Comments(
            content=form.content.data,
            object_id = news_id
        )
        reply_id = form.reply_id.data
        if reply_id:
            comment_obj.reply_id = reply_id
        # 保存数据
        comment_obj.save()
        flash("评论成功")
        return redirect(url_for('detail',pk=news_id))
    else:
        print("评论添加失败")
    return render_template("detail.html",form=form,new_obj=new_obj)

# 后台管理 - -评论管理页
@app.route('/admin/comment')
@app.route('/admin/comment/<int:page>/')
def admin_comment(page=1):
    # 后台管理 - -评论管理页
    # 第二种分页方式  前端页面循环用page_data.items
    page_size = 5
    page_data = Comments.objects.all()
    page_data = page_data.paginate(page=page,per_page=page_size)
    # 第二种方式的page_data  是一个对象里面有很多属性和方法items、has_prev、iter_pages()等等  前端页面可以调用
    return render_template('admin/comments.html',page_data=page_data)


# 后台管理--删除新闻
@app.route("/admin/comment/delete/<string:pk>",methods=['POST'])
def comment_delete(pk):
    # 异步ajax删除 逻辑删除评论
    if request.method == 'POST':
        comment_obj = Comments.objects.filter(id=pk).first()
        # 评论不存在
        if comment_obj is None:
            return 'no'
        # 评论已经被删除掉了
        if not comment_obj.is_valid:
            return 'no'
        comment_obj.is_valid = False
        comment_obj.save()
        return 'yes'
    return 'no'

# 后台管理--新闻首页
@app.route('/admin/')
@app.route('/admin/<int:page>/')
def admin(page=1):
    # 后台管理 - -新闻首页
    # 第一种分页方式  前端页面循环用page_data
    # page_size = 3
    # offset = (page - 1) * page_size
    # page_data = News.query.limit(page_size).offset(offset)
    # 第二种分页方式  前端页面循环用page_data.items
    page_data = News.query.filter(News.is_valid == 1).order_by(News.created_at.desc()).paginate(page=page,per_page=3)
    # 第二种方式的page_data  是一个对象里面有很多属性和方法items、has_prev、iter_pages()等等  前端页面可以调用
    return render_template('admin/index.html',page_data=page_data)

# 后台管理--新增新闻(/admin/add和/admin/add/ 有时报404  是浏览器缓存问题)
@app.route("/admin/add",methods=("GET","POST"))
def news_add():
    # "新增新闻"
    form = NewsForm_mysql()
    if form.validate_on_submit():
        news_obj = News(
            title=form.title.data,
            content=form.content.data,
            img_url=form.img_url.data,
            is_top=form.is_top.data,
            news_type=form.news_type.data,
            created_at=datetime.now()
        )
        # 保存数据
        db.session.add(news_obj)
        db.session.commit()
        # 添加的时候缓存置顶新闻到redis中
        if news_obj.is_top:
            cache_obj = NewsCache()
            cache_obj.set_index_news()
        flash("新增成功")
        return redirect(url_for('admin'))
    else:
        print("表单添加失败")
    return render_template("admin/add.html",form=form)

# 后台管理--修改新闻
@app.route("/admin/update/<int:pk>",methods=["GET","POST"])
def news_update(pk):
    # '后台管理--修改新闻'
    new_obj = News.query.get(pk)
    print(new_obj)
    if new_obj is None:
        abort(404)
    form = NewsForm_mysql(obj = new_obj)
    is_top_origin = new_obj.is_top
    if request.method == 'POST':
        if form.validate_on_submit():
            is_top = form.is_top.data
            new_obj.title = form.title.data
            new_obj.content = form.content.data
            new_obj.img_url = form.img_url.data
            new_obj.news_type = form.news_type.data
            new_obj.is_top = is_top
            new_obj.updated_at = datetime.now()
            db.session.add(new_obj)
            db.session.commit()
            # 修改新闻的时候  更新缓存
            if is_top_origin != is_top:
                cache_obj = NewsCache()
                cache_obj.set_index_news()
            print('修改成功')
            flash('修改成功','success')
            return redirect('/admin/')
        else:
            flash('你的表单中还有错误，请修改','danger')
            print('表单没有通过验证',form.errors)

    return render_template("admin/update.html",form=form)

# 后台管理--删除新闻
@app.route("/admin/delete/<pk>",methods=['POST'])
def news_delete(pk):
    # 异步ajax删除 逻辑删除
    if request.method == 'POST':
        obj = News.query.get(pk)
        # 新闻不存在
        if obj is None:
            return 'no'
        # 新闻已经被删除掉了
        if not obj.is_valid:
            return 'no'
        obj.is_valid = False
        db.session.add(obj)
        db.session.commit()
        # 删除新闻的时候  更新缓存
        if obj.is_top:
            cache_obj = NewsCache()
            cache_obj.set_index_news()
        return 'yes'
    return 'no'

# 后台管理--查看新闻(前台有详情  此处没必要)
@app.route("/admin/detail/<pk>",methods=['GET'])
def news_detail(pk):
    pass
    # # 新闻详情页
    # new_obj = News.query.get(pk)
    # if not new_obj.is_valid:
    #     abort(404)
    # return render_template('admin/update.html', new_obj=new_obj)


if __name__ == '__main__':
    # app.run()
    app.run(host='127.0.0.1', port=5000, debug=True)  # 必须指定 host
